module alu(
input [7:0] a, b, //input data
input [2:0] op, //opcode
output [7:0] r, //result data
output zero //zero bit
); //8-bit ALU. Signed 8-bit 

//ALU doesn't need clock, because there are no clock-triggered operations

wire [7:0] addr; //result of add
wire [7:0] subr; //result of sub
wire [7:0] andr; //result of and
wire [7:0] orr; //result of or
wire [7:0] sltr; //result of slt

alu_add addop(a,b,1'b0,addr);
alu_add subop(a,~b,1'b1,subr);
alu_or orop(a,b,orr);
alu_and andop(a,b,andr);
alu_slt sltop(a,b,sltr);

alu_mux am(op, addr, subr, andr, orr, sltr, r);

nor(zero, r[0], r[1], r[2], r[3],r[4], r[5], r[6], r[7]);

endmodule

module alu_mux_1bit(
input [2:0] op, //opcode
input addr, subr, andr, orr, sltr, //candidates
output r //result
); //mux for which result will be chosen

wire [4:0] m; //wire between gates

and(m[0], andr, ~op[2], ~op[1], ~op[0]); //and op : 000
and(m[1], orr, ~op[2], ~op[1], op[0]); //or op : 001
and(m[2], addr, ~op[2], op[1], ~op[0]); //add op : 010
and(m[3], subr, op[2], op[1], ~op[0]); //sub op : 110
and(m[4], sltr, op[2], op[1], op[0]); //slt op : 111

or(r, m[0], m[1], m[2], m[3], m[4]);

endmodule

module alu_mux(
input [2:0] op,
input [7:0] addr, subr, andr, orr, sltr, 
output [7:0] r
);

alu_mux_1bit m0(op, addr[0], subr[0], andr[0], orr[0], sltr[0], r[0]);
alu_mux_1bit m1(op, addr[1], subr[1], andr[1], orr[1], sltr[1], r[1]);
alu_mux_1bit m2(op, addr[2], subr[2], andr[2], orr[2], sltr[2], r[2]);
alu_mux_1bit m3(op, addr[3], subr[3], andr[3], orr[3], sltr[3], r[3]);
alu_mux_1bit m4(op, addr[4], subr[4], andr[4], orr[4], sltr[4], r[4]);
alu_mux_1bit m5(op, addr[5], subr[5], andr[5], orr[5], sltr[5], r[5]);
alu_mux_1bit m6(op, addr[6], subr[6], andr[6], orr[6], sltr[6], r[6]);
alu_mux_1bit m7(op, addr[7], subr[7], andr[7], orr[7], sltr[7], r[7]);

endmodule

module alu_and(
input [7:0] a,b,
output [7:0] r
); //8-bit and operation
and(r[0], a[0], b[0]);
and(r[1], a[1], b[1]);
and(r[2], a[2], b[2]);
and(r[3], a[3], b[3]);
and(r[4], a[4], b[4]);
and(r[5], a[5], b[5]);
and(r[6], a[6], b[6]);
and(r[7], a[7], b[7]);

endmodule

module alu_or(
input [7:0] a,b,
output [7:0] r
); //8-bit and operation
or(r[0], a[0], b[0]);
or(r[1], a[1], b[1]);
or(r[2], a[2], b[2]);
or(r[3], a[3], b[3]);
or(r[4], a[4], b[4]);
or(r[5], a[5], b[5]);
or(r[6], a[6], b[6]);
or(r[7], a[7], b[7]);

endmodule


module alu_slt(
input [7:0] a,b,
output [7:0] r
); //8-bit slt operation

wire [7:0] test; //a-b

alu_add slt_sub(a,~b,1'b1,test);

assign r[7:1]=0;

assign r[0]=test[7];

endmodule


module alu_add(
input [7:0] a,b,
input cin, //carry in
output [7:0] r
); //8-bit adder

wire [7:1] c; //carry bits
wire [23:0] m; //wires for between value

wire cout;

xor(r[0], a[0], b[0], cin);
and(m[0], a[0], b[0]);
or(m[1], a[0], b[0]);
and(m[2], m[1], cin);
or(c[1], m[2], m[0]);

xor(r[1], a[1], b[1], c[1]);
and(m[3], a[1], b[1]);
or(m[4], a[1], b[1]);
and(m[5], m[4], c[1]);
or(c[2], m[3], m[5]);

xor(r[2], a[2], b[2], c[2]);
and(m[6], a[2], b[2]);
or(m[7], a[2], b[2]);
and(m[8], m[7], c[2]);
or(c[3], m[6], m[8]);

xor(r[3], a[3], b[3], c[3]);
and(m[9], a[3], b[3]);
or(m[10], a[3], b[3]);
and(m[11], m[10], c[3]);
or(c[4], m[9], m[11]);

xor(r[4], a[4], b[4], c[4]);
and(m[12], a[4], b[4]);
or(m[13], a[4], b[4]);
and(m[14], m[13], c[4]);
or(c[5], m[12], m[14]);

xor(r[5], a[5], b[5], c[5]);
and(m[15], a[5], b[5]);
or(m[16], a[5], b[5]);
and(m[17], m[16], c[5]);
or(c[6], m[15], m[17]);

xor(r[6], a[6], b[6], c[6]);
and(m[18], a[6], b[6]);
or(m[19], a[6], b[6]);
and(m[20], m[19], c[6]);
or(c[7], m[18], m[20]);

xor(r[7], a[7], b[7], c[7]);
and(m[21], a[7], b[7]);
or(m[22], a[7], b[7]);
and(m[23], m[22], c[7]);
or(cout, m[21], m[23]);

endmodule